(def book {:title "1Q84" :author "村上春樹"})

(def anotherbook (assoc book :publisher "新潮社"))

(= book anotherbook)
;=> false

(= book (dissoc anotherbook :publisher))
;=> true

* Var

(def v 1)

(println v) ; -> 1

(binding [v 23] (println v))  ;-> 23

(do
  (binding [v 456]
    (println v))
  (println v))
; -> 456
;     1

* Ref

(def cd (ref {:title "Orchestrion" :artist "Pat Metheny"}))
cd
(deref cd)
@cd

** ref-set
(ref-set cd {:price 2680 :genre "Jazz"})
; => java.lang.IllegalStateException: No transaction running (NO_SOURCE_FILE:0)

(dosync (ref-set cd {:price 2680 :genre "Jazz"}))
; => {:price 2680, :genre "Jazz"}

@cd
; => {:price 2680, :genre "Jazz"}

** alter

(alter cd assoc :year 2010)
; => java.lang.IllegalStateException: No transaction running (NO_SOURCE_FILE:0)

(dosync (alter cd assoc :year 2010))
; => {:year 2010, :title "Orchestrion", :artist "Pat Metheny"}

@cd
; => {:year 2010, :title "Orchestrion", :artist "Pat Metheny"}

** commute

(dosync (commute cd assoc :year 2010))
; => {:year 2010, :title "Orchestrion", :artist "Pat Metheny"}

@cd
; => {:year 2010, :title "Orchestrion", :artist "Pat Metheny"}

(import '(java.lang Thread))
(defmacro with-new-thread [& body]
  `(.start (Thread. (fn [] ~@body))))

(def logs (ref ""))
(dosync (ref-set logs ""))

(with-new-thread
  (dosync
   (println "--スレッドA 更新開始:" @logs)
   (alter logs str "A")
   (println "--スレッドA 更新完了:" @logs)
   (Thread/sleep 4000)
   (println "--スレッドA 終了:" @logs)))
(with-new-thread
  (dosync
   (println "****スレッドB 更新開始:" @logs)
   (Thread/sleep 1000)
   (alter logs str "B")
   (println "****スレッドB 更新完了:" @logs)
   (println "****スレッドB 終了:" @logs)))

(do
  (with-new-thread
    (dosync
     (println "--スレッドA 更新開始:" @logs)
     (alter logs str "A")
     (println "--スレッドA 更新完了:" @logs)
     (Thread/sleep 4000)
     (println "--スレッドA 終了:" @logs)))
  (Thread/sleep 10)
  (with-new-thread
    (dosync
     (println "****スレッドB 更新開始:" @logs)
     (Thread/sleep 1000)
     (alter logs str "B")
     (println "****スレッドB 更新完了:" @logs)
     (println "****スレッドB 終了:" @logs))))

** alter, alter
--スレッドA 更新開始:
--スレッドA 更新完了: A
****スレッドB 更新開始:
****スレッドB 更新開始:
****スレッドB 更新開始:
****スレッドB 更新開始:
--スレッドA 終了: A
****スレッドB 更新開始: A
****スレッドB 更新完了: AB
****スレッドB 終了: AB

** alter, commute
--スレッドA 更新開始:
--スレッドA 更新完了: A
****スレッドB 更新開始:
****スレッドB 更新完了: B
****スレッドB 終了: B
****スレッドB 更新開始:
****スレッドB 更新完了: B
****スレッドB 終了: B
****スレッドB 更新開始:
****スレッドB 更新完了: B
****スレッドB 終了: B
****スレッドB 更新開始:
--スレッドA 終了: A
****スレッドB 更新完了: AB
****スレッドB 終了: AB

** commute, alter
--スレッドA 更新開始:
--スレッドA 更新完了: A
****スレッドB 更新開始:
****スレッドB 更新完了: B
****スレッドB 終了: B
--スレッドA 終了: A

@logs
;=> "BA"

** ensure
--スレッドA 更新開始:
--スレッドA 更新完了: A
--スレッドA 終了: A
****スレッドB 更新開始: A
****スレッドB 更新完了: AB
****スレッドB 終了: AB


* Atom
(def song (atom {:title "リハーサル" :artist "近藤夏子"}))
song
(deref song)
@song

(reset! song {:title "sad to say" :artist "Jasmine"})
(reset! song {:title "リハーサル" :artist "近藤夏子"})
(swap! song assoc :title "リアルでゴメン...")


* Agent

(def fetcher (agent ""))

(use '[clojure.contrib.io :only (slurp*)])
(defn fetch-title
  [_ url]
  (Thread/sleep 2000)
  (second (re-find #"<title>(.*?)</title>" (slurp* url))))

(do
  (send fetcher fetch-title "http://bit.ly/")
  (println "send 直後: " @fetcher)
  (Thread/sleep 1000)
  (println "send 1秒後: " @fetcher)
  (Thread/sleep 3000)
  (println "send 4秒後: " @fetcher))

(do
  (send fetcher fetch-title "http://bit.ly/")
  (await-for 1500 fetcher)
  (println "await-for 直後: " @fetcher)
  (Thread/sleep 3000)
  (println "await-for 3秒後: " @fetcher))

(time
 (do
   (send fetcher fetch-title "http://www.google.com/")
   (send fetcher fetch-title "http://www.apple.com/")
   (send fetcher fetch-title "http://www.yahoo.com/")
   (await fetcher)
   (println "終了: " @fetcher)))


(send fetcher (fn [_] ""))

(send fetcher fetch-title "http://notfound/")

(agent-errors fetcher)
(clear-agent-errors fetcher)

* pmap

(defn heavy-double
  [n]
  (Thread/sleep 1000)
  (* 2 n))

(time (doall (map #(heavy-double %) (range 10))))
(time (doall (pmap #(heavy-double %) (range 10))))

(use '[clojure.contrib.io :only (slurp*)])
(def urls ["http://www.apple.com/jp/"
           "http://www.cookpad.com/"
           "http://www.nicovideo.jp/"
           "http://b.hatena.ne.jp/"
           "http://japan.cnet.com/"
           "http://ja.wikipedia.org/"])

(defn fetch-title
  [url]
  (second (re-find #"<title>(.*?)</title>" (slurp* url))))

(map #(fetch-title %) urls)
(time (doall (map #(fetch-title %) urls)))
(time (doall (pmap #(fetch-title %) urls)))
